package com.app.island.cash.requestwork

import com.app.island.cash.params.AppParams
import com.app.island.cash.utilstools.SystemUtils
import com.app.island.cash.utilstools.UserInfoManager
import com.google.gson.Gson
import okhttp3.*
import okio.Buffer
import java.io.File
import java.io.IOException
import java.net.URLDecoder
import java.net.URLEncoder
import java.util.*

class CustomerInterceptor : Interceptor {
    var headerParamsMap: MutableMap<String, String> = HashMap()
    var commomParams: TreeMap<String?, String?> = TreeMap()

    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {
        var request = chain.request()
        val requestBuilder = request.newBuilder()
        val headerBuilder = request.headers.newBuilder()

        headerParamsMap.clear()
        commomParams.clear()
        commomParams["mobileType"] = "2"
        commomParams["client"] = "Android"
        commomParams["versionNumber"] = SystemUtils.versionName
        commomParams["channelCode"] = AppParams.channel
        commomParams["appFlag"] = AppParams.flag
        if (UserInfoManager.instance.isLogin) {
            commomParams["userId"] = UserInfoManager.instance.uid
            commomParams["token"] = UserInfoManager.instance.token
        }

        headerParamsMap.clear()
        headerParamsMap = if (request.method == "POST") {
            if (null != request.body && request.body is MultipartBody) {
                HashMap()
            } else {
                val signMap: SortedMap<String?, String?> = TreeMap(commomParams)
                val bodyToMap = requestBodyToMap(request.body)
                bodyToMap?.let {
                    it.entries.forEach {itt->
                        signMap[itt.key.toString()] = itt.value.toString()
                    }
                }
                signHeadParams(signMap)
            }
        } else {
            signHeadParams(getUrlToMap(request.url.toString(), commomParams))
        }

        //set header
        if (headerParamsMap.isNotEmpty()) {
            for ((key, value) in headerParamsMap) {
                headerBuilder.add(key, value)
            }
        }
        requestBuilder.headers(headerBuilder.build())

        //set body
        if (request.method == "POST") {
            if (null != request.body && request.body is MultipartBody) {
//                val multipartBodyBuilder = MultipartBody.Builder()
//                multipartBodyBuilder.setType(MultipartBody.FORM)
//                // add new params to new multipartBodyBuilder
//                if (commomParams.size > 0) {
//                    for ((key, value) in commomParams) {
//                        multipartBodyBuilder.addFormDataPart(key!!, value!!)
//                    }
//                }
//                // add old parts to new multipartBodyBuilder
//                for (part in (request.body as MultipartBody?)!!.parts) {
//                    multipartBodyBuilder.addPart(part)
//                }
//                requestBuilder.post(multipartBodyBuilder.build())
            } else {
                val formBodyBuilder = FormBody.Builder()
                // add new params to new formBodyBuilder
                if (commomParams.size > 0) {
                    for ((key, value) in commomParams) {
                        formBodyBuilder.add(key!!, value!!)
                    }
                }
                // add old params to new formBodyBuilder
                val formBody = formBodyBuilder.build()
                val finalBodyMap: SortedMap<String?, String?> = TreeMap()
                val bodyToMap = requestBodyToMap(request.body)
                bodyToMap?.let {
                    it.entries.forEach {itt->
                        finalBodyMap[itt.key.toString()] = itt.value.toString()
                    }
                }
                if (commomParams!!.isNotEmpty()) {
                    commomParams.entries.forEach {
                        finalBodyMap[it.key.toString()] = it.value.toString()
                    }
                }
                val postParamsStr = getPostParamsStr(finalBodyMap)
                requestBuilder.post(RequestBody.create(formBody.contentType(), postParamsStr))
            }
        } else {
            injectParamsIntoUrl(request, requestBuilder, commomParams)
        }
        request = requestBuilder.build()
        return chain.proceed(request)
    }

    private fun signHeadParams(bodyParamsMap: SortedMap<String?, String?>): SortedMap<String, String> {
        val sign = mapToSignMsg(bodyParamsMap)
        val headMap: SortedMap<String, String> = TreeMap()
        headMap["signMsg"] = sign
        headMap["token"] = UserInfoManager.instance.token
        return headMap
    }

    private fun mapToSignMsg(bodyParamsMap: SortedMap<String?, String?>): String {
        var sign = ""
        try {
            val it: Iterator<*> = bodyParamsMap.entries.iterator()
            val sb = StringBuilder()
            while (it.hasNext()) {
                val entry = it.next() as Map.Entry<*, *>
                if (entry.value is File) continue  //URLEncoder.encode(, "UTF-8")
                sb.append(entry.key).append("=")
                    .append(entry.value.toString()).append("|")
            }
            sign = if (sb.toString().length > 1) {
                sb.toString().substring(0, sb.length - 1)
            } else {
                sb.toString()
            }
            sign = SystemUtils.md5( AppParams.SIGN_KEY + UserInfoManager.instance.token + sign)
        } catch (e: Exception) {
            e.printStackTrace()
            sign = ""
        }
        return sign
    }

    private fun getUrlToMap(
        url: String,
        bodyParamsMap: SortedMap<String?, String?>
    ): SortedMap<String?, String?> {
        val signMap: SortedMap<String?, String?> = TreeMap()
        signMap.putAll(bodyParamsMap)
        if (url.split("\\?".toRegex()).toTypedArray().size > 1) {
            val paramStr = url.split("\\?".toRegex()).toTypedArray()[1]
            val params = paramStr.split("&".toRegex()).toTypedArray()
            var temp: SortedMap<String?, String?>
            for (i in params.indices) {
                temp = TreeMap()
                val s = params[i].split("=".toRegex()).toTypedArray()
                if (s.size > 1) {
                    temp[s[0]] = URLDecoder.decode(s[1], "UTF-8")
                } else {
                    temp[s[0]] = ""
                }
                signMap.putAll(temp)
            }
        }
        return signMap
    }

    // func to inject params into url
    private fun injectParamsIntoUrl(
        request: Request,
        requestBuilder: Request.Builder,
        paramsMap: Map<String?, String?>
    ) {
        val httpUrlBuilder = request.url.newBuilder()
        if (paramsMap.isNotEmpty()) {
            for ((key, value) in paramsMap) {
                httpUrlBuilder.addQueryParameter(key!!, value)
            }
        }
        requestBuilder.url(httpUrlBuilder.build())
    }

    private fun requestBodyToMap(requestBody: RequestBody?): SortedMap<*, *>? {
        return try {
            val buffer = Buffer()
            requestBody?.writeTo(buffer)
            val result = buffer.readUtf8()
            try {
                Gson().fromJson(result, SortedMap::class.java)
            } catch (e: Exception) {
                null
            }
        } catch (e: IOException) {
            null
        }
    }

    private fun getPostParamsStr(map: SortedMap<*, *>?): String {
        val it: Iterator<*> = map!!.entries.iterator()
        val sb = StringBuilder()
        try {
            while (it.hasNext()) {
                val entry = it.next() as Map.Entry<*, *>
                sb.append(entry.key).append("=")
                    .append(URLEncoder.encode(entry.value.toString(), "UTF-8")).append("&")
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return if (sb.toString().length > 1) {
            sb.toString().substring(0, sb.length - 1)
        } else {
            sb.toString()
        }
    }
}